import { Context } from 'koa';
import { ResponseUtil } from '@/utils/response';
import { logger } from '@/utils/logger';
import { AppError } from '@/middlewares/error';
import { PaginatedResult, PaginationQuery } from '@/types';
import { MulterFile } from '@/types/express';

/**
 * 基础控制器类
 */
export abstract class BaseController {
  /**
   * 处理成功响应
   */
  protected success<T>(ctx: Context, data?: T, message?: string, statusCode?: number): void {
    ctx.status = statusCode || 200;
    ctx.body = ResponseUtil.success(data, message, statusCode);
  }

  /**
   * 处理创建响应
   */
  protected created<T>(ctx: Context, data?: T, message?: string): void {
    ctx.status = 201;
    ctx.body = ResponseUtil.created(data, message);
  }

  /**
   * 处理分页响应
   */
  protected paginated<T>(
    ctx: Context,
    result: PaginatedResult<T>,
    message?: string
  ): void {
    ctx.status = 200;
    ctx.body = ResponseUtil.paginated(
      result.data,
      result.pagination.page,
      result.pagination.limit,
      result.pagination.total,
      message
    );
  }

  /**
   * 处理错误响应
   */
  protected error(ctx: Context, message: string, statusCode?: number): void {
    const code = statusCode || 500;
    ctx.status = code;
    ctx.body = ResponseUtil.error(message, code, ctx.path);
  }

  /**
   * 获取分页参数
   */
  protected getPaginationQuery(ctx: Context): PaginationQuery {
    const page = parseInt(ctx.query.page as string) || 1;
    const limit = Math.min(parseInt(ctx.query.limit as string) || 10, 100);
    const sortBy = ctx.query.sortBy as string || 'createdAt';
    const sortOrder = (ctx.query.sortOrder as string) === 'asc' ? 'asc' : 'desc';
    const keyword = ctx.query.keyword as string || '';

    return {
      page,
      limit,
      sortBy,
      sortOrder,
      keyword,
    };
  }

  /**
   * 获取请求用户信息
   */
  protected getCurrentUser(ctx: Context): { id: string; email: string; role: string } | null {
    return ctx.state.user || null;
  }

  /**
   * 验证用户权限
   */
  protected requireAuth(ctx: Context): { id: string; email: string; role: string } {
    const user = this.getCurrentUser(ctx);
    if (!user) {
      throw new AppError('需要登录', 401);
    }
    return user;
  }

  /**
   * 验证管理员权限
   */
  protected requireAdmin(ctx: Context): { id: string; email: string; role: string } {
    const user = this.requireAuth(ctx);
    if (user.role !== 'admin') {
      throw new AppError('需要管理员权限', 403);
    }
    return user;
  }

  /**
   * 验证资源所有者权限
   */
  protected requireOwnership(
    ctx: Context,
    resourceUserId: string
  ): { id: string; email: string; role: string } {
    const user = this.requireAuth(ctx);
    
    // 管理员可以访问所有资源
    if (user.role === 'admin') {
      return user;
    }
    
    // 检查是否为资源所有者
    if (user.id !== resourceUserId) {
      throw new AppError('权限不足', 403);
    }
    
    return user;
  }

  /**
   * 记录操作日志
   */
  protected logAction(
    action: string,
    userId?: string,
    details?: Record<string, unknown>
  ): void {
    logger.info({
      action,
      userId,
      details,
      timestamp: new Date().toISOString(),
    }, `用户操作: ${action}`);
  }

  /**
   * 处理异步操作
   */
  protected async handleAsync<T>(
    operation: () => Promise<T>,
    errorMessage: string = '操作失败'
  ): Promise<T> {
    try {
      return await operation();
    } catch (error) {
      logger.error(error, errorMessage);
      
      if (error instanceof AppError) {
        throw error;
      }
      
      throw new AppError(errorMessage, 500);
    }
  }

  /**
   * 验证ID格式
   */
  protected validateId(id: string): void {
    if (!id || !/^[0-9a-fA-F]{24}$/.test(id)) {
      throw new AppError('无效的ID格式', 400);
    }
  }

  /**
   * 获取查询过滤器
   */
  protected getQueryFilter(ctx: Context, allowedFields: string[]): Record<string, unknown> {
    const filter: Record<string, unknown> = {};
    
    allowedFields.forEach(field => {
      const value = ctx.query[field];
      if (value !== undefined && value !== '') {
        filter[field] = value;
      }
    });
    
    return filter;
  }

  /**
   * 构建排序对象
   */
  protected buildSort(sortBy: string, sortOrder: 'asc' | 'desc'): Record<string, 1 | -1> {
    return { [sortBy]: sortOrder === 'asc' ? 1 : -1 };
  }

  /**
   * 构建搜索查询
   */
  protected buildSearchQuery(
    keyword: string,
    searchFields: string[]
  ): Record<string, unknown> {
    if (!keyword.trim()) {
      return {};
    }

    const searchConditions = searchFields.map(field => ({
      [field]: { $regex: keyword, $options: 'i' }
    }));

    return { $or: searchConditions };
  }

  /**
   * 验证请求数据
   */
  protected validateRequestData(data: unknown, requiredFields: string[]): void {
    if (!data || typeof data !== 'object') {
      throw new AppError('请求数据格式错误', 400);
    }

    const dataObj = data as Record<string, unknown>;
    
    for (const field of requiredFields) {
      if (dataObj[field] === undefined || dataObj[field] === null || dataObj[field] === '') {
        throw new AppError(`缺少必需字段: ${field}`, 400);
      }
    }
  }

  /**
   * 清理响应数据
   */
  protected sanitizeResponse<T extends Record<string, unknown>>(
    data: T,
    excludeFields: string[] = []
  ): Partial<T> {
    const sanitized = { ...data };
    
    // 默认排除的敏感字段
    const defaultExcludeFields = ['password', '__v', 'deletedAt'];
    const fieldsToExclude = [...defaultExcludeFields, ...excludeFields];
    
    fieldsToExclude.forEach(field => {
      delete sanitized[field];
    });
    
    return sanitized;
  }

  /**
   * 处理文件上传
   */
  protected getUploadedFile(ctx: Context, fieldName: string = 'file'): MulterFile | null {
    const files = ctx.request.files as { [fieldname: string]: MulterFile[] } | undefined;
    
    if (!files || !files[fieldName] || files[fieldName].length === 0) {
      return null;
    }
    
    return files[fieldName][0] || null;
  }

  /**
   * 验证文件类型
   */
  protected validateFileType(file: MulterFile, allowedTypes: string[]): void {
    if (!allowedTypes.includes(file.mimetype)) {
      throw new AppError(`不支持的文件类型: ${file.mimetype}`, 400);
    }
  }

  /**
   * 验证文件大小
   */
  protected validateFileSize(file: MulterFile, maxSize: number): void {
    if (file.size > maxSize) {
      throw new AppError(`文件大小超出限制: ${maxSize} bytes`, 400);
    }
  }
}

export default BaseController;